import Http from 'axios'

const createOfdConvertTaskUrl = `/xsajbl-service/api/caseDocPrinting/convertToOfd`
const createPdfConvertTaskUrl = `/xsajbl-service/api/caseDocPrinting/convertToPdf`
const queryConvertTaskUrl = `/xsajbl-service/api/caseDocPrinting/queryProcessState`
const saveConvertedFileUrl = `/xsajbl-service/api/caseDocPrinting/saveOfdByTicket`

// 书生的接口要求每次加载的OFD阅读器ID唯一
const idGenerator = 0

// TODO 书生支持哪些格式?
function ensureFormat(format) {
  switch (format) {
    case 'doc':
    case 'docx':
    case 'wps':
    case 'xlsx':
    case 'xls':
    case 'xltx':
    case 'ppt':
    case 'pptx':
    case 'et':
    case 'rtf':
    case 'txt':
    case 'pdf':
    case 'png':
    case 'jpeg':
    case 'ico':
    case 'gif':
    case 'jpg':
    case 'tiff':
    case 'tif':
    case 'bmp':
      break
    default:
      console.log('目前支持转为版式文件的源文件格式有: doc/docx/wps/xls/xlsx/pdf/png/jpeg/jpg/bmp')
      throw Error(`不受格式转换支持的格式: ${format}`)
  }
}

function isSursenLocalPluginUsable() {
  for (let i = 0; i < navigator.mimeTypes.length; i++) {
    if (navigator.mimeTypes[i].type === 'trivial/very') {
      return true
    }
  }

  return false
}

async function askServerDownloadFile(
  targetDir,
  targetName,
  overrideOnExists,
  ticket,
  saveServerUrl,
  format,
  wsslbh,
  sfyy,
) {
  // 由于目前书生的转版接口是同步的，在改称异步之前， ticket的值就是下载链接

  const result = await Http.post(saveServerUrl, {
    targetDir: targetDir,
    targetName: targetName,
    overrideOnExists: overrideOnExists,
    ticket: ticket,
    wjkzm: format.toLowerCase(),
    wsslbh: wsslbh,
    // 打开方式：2 表示转版成功
    dkfs: 2,
    sfyy: sfyy,
  })

  if (!result) {
    throw Error(`请求服务器保存转版文件失败`)
  }
  if (!result.success) {
    console.log(result)
    throw Error(`请求服务器保存转版文件失败: ${result.message}`)
  }

  return result
}

async function doConvert({
  serverUrl,
  sourceDir,
  sourceName,
  targetDir,
  targetName,
  format,
  overrideOnExists,
  queryServerUrl,
  saveServerUrl,
  wsslbh,
  targetFormat,
  maxQueryTimes,
  sfyy,
  createExtend,
}) {
  ensureFormat(format)

  const result = await Http.post(serverUrl, {
    sourceDir: sourceDir,
    sourceName: sourceName,
    format: format,
    createExtend: createExtend,
  })

  if (!result) {
    throw Error(`请求文档转换失败`)
  }
  if (!result.success) {
    console.log(result)
    throw Error(`请求文档转换失败: ${result.message}`)
  }

  const sursenResult = JSON.parse(result.data)
  console.log(sursenResult)

  if (!sursenResult || sursenResult.statusCode !== 0) {
    throw Error(`请求文档转换失败: ${sursenResult.message}`)
  }

  const ticket = sursenResult.data

  console.log(ticket)

  await pollingUntilFinish(ticket, queryServerUrl, maxQueryTimes)

  return askServerDownloadFile(
    targetDir,
    targetName,
    overrideOnExists,
    ticket,
    saveServerUrl,
    targetFormat,
    wsslbh,
    sfyy,
  )
}

async function pollingUntilFinish(ticket, queryServerUrl, maxQueryTimes) {
  let times = 1
  maxQueryTimes = maxQueryTimes || 15
  const gap = 1500

  while (true) {
    // 每隔1.5秒查询一次
    await sleep(gap)

    const result = await Http.post(queryServerUrl, {
      ticket: ticket,
    })

    if (!result || !result.success) {
      console.log(result)
      console.error(`查询文档转换进度失败, ${gap}毫秒后继续重试查询, ticket: ${ticket}`)
      continue
    }

    const sursenResult = JSON.parse(result.data)

    if (sursenResult.statusCode === 0) {
      return
    } else if (sursenResult.statusCode === 1) {
      console.log(`转版任务尚未开始, ${gap}毫秒后继续重试查询, ticket: ${ticket}`)
    } else if (sursenResult.statusCode === 2) {
      console.log(`转版任务正在进行, ${gap}毫秒后继续重试查询, ticket: ${ticket}`)
    } else {
      console.log(sursenResult)
      throw Error(`转版任务执行失败: ticket: ${ticket}, 错误信息: ${sursenResult.message}`)
    }

    if (times++ >= maxQueryTimes) {
      throw Error(`文件未在${1.5 * maxQueryTimes}秒内完成转版, 取消等待. ticket: ${ticket}`)
    }
  }
}

function ensureBatchPrinterLoaded() {
  const id = '__sursensedoi__'
  if (!document.getElementById(id)) {
    const batchPrinter = document.createElement('embed')
    batchPrinter.setAttribute('type', 'application/SursenOFD-plugin')
    batchPrinter.setAttribute('id', id)
    batchPrinter.setAttribute('style', 'width: 0;height: 0; visibility: hidden')

    document.getElementsByTagName('body')[0].appendChild(batchPrinter)

    fileConverter.batchPrinter = batchPrinter
  }
}

const fileConverter = {
  /**
   * 将文档转换为版式文件
   * @param sourceDir 源文档在存储中的dir
   * @param sourceName 源文档在存储中的name
   * @param targetDir 转换完成后的版式文件在存储中存放的dir
   * @param targetName 转换完成后的版式文件在存储中存放的name
   * @param format 源文档的格式, 如: wps/doc/docx等
   * @param overrideOnExists 当转targetDir/targetName 对应的文件已存在时是否强制覆盖
   * @param convertServerUrl 创建转版任务的地址，默认请求刑事案件办理的接口
   * @param queryServerUrl 查询转版任务的地址，默认请求刑事案件办理的接口
   * @param saveServerUrl 请求下载转版后文件的地址，默认请求刑事案件办理的接口
   * @param wsslbh 文书实例编号
   * @param maxQueryTimes 查询转版进度最多尝试次数， 每次间隔1.5秒
   * @param sfyy 是否用印
   * @param createExtend 创建转版任务的扩展参数，业务层自行定义
   *
   * @throws 网络请求异常或者转换失败的时候会抛出异常
   */
  toOFD: async ({
    sourceDir,
    sourceName,
    targetDir,
    targetName,
    format,
    overrideOnExists,
    convertServerUrl,
    queryServerUrl,
    saveServerUrl,
    wsslbh,
    maxQueryTimes,
    sfyy,
    createExtend,
  }) => {
    return doConvert({
      sourceDir: sourceDir,
      sourceName: sourceName,
      targetDir: targetDir,
      targetName: targetName,
      format: format,
      overrideOnExists: overrideOnExists,
      serverUrl: convertServerUrl || createOfdConvertTaskUrl,
      queryServerUrl: queryServerUrl || queryConvertTaskUrl,
      saveServerUrl: saveServerUrl || saveConvertedFileUrl,
      wsslbh: wsslbh,
      targetFormat: 'ofd',
      maxQueryTimes: maxQueryTimes,
      sfyy: sfyy,
      createExtend: createExtend,
    })
  },
  /**
   * 将文档转换为版式文件
   * @param sourceDir 源文档在存储中的dir
   * @param sourceName 源文档在存储中的name
   * @param targetDir 转换完成后的版式文件在存储中存放的dir
   * @param targetName 转换完成后的版式文件在存储中存放的name
   * @param format 源文档的格式, 如: wps/doc/docx等
   * @param overrideOnExists 当转targetDir/targetName 对应的文件已存在时是否强制覆盖
   * @param convertServerUrl 创建转版任务的地址，默认请求刑事案件办理的接口
   * @param queryServerUrl 查询转版任务的地址，默认请求刑事案件办理的接口
   * @param saveServerUrl 请求下载转版后文件的地址，默认请求刑事案件办理的接口
   * @param wsslbh 文书实例编号
   * @param maxQueryTimes 查询转版进度最多尝试次数， 每次间隔1.5秒
   * @param sfyy 是否用印
   * @param createExtend 创建转版任务的扩展参数，业务层自行定义
   *
   * @throws 网络请求异常或者转换失败的时候会抛出异常
   */
  toPDF: async ({
    sourceDir,
    sourceName,
    targetDir,
    targetName,
    format,
    overrideOnExists,
    convertServerUrl,
    queryServerUrl,
    saveServerUrl,
    wsslbh,
    maxQueryTimes,
    sfyy,
    createExtend,
  }) => {
    return doConvert({
      sourceDir: sourceDir,
      sourceName: sourceName,
      targetDir: targetDir,
      targetName: targetName,
      format: format,
      overrideOnExists: overrideOnExists,
      serverUrl: convertServerUrl || createPdfConvertTaskUrl,
      queryServerUrl: queryServerUrl || queryConvertTaskUrl,
      saveServerUrl: saveServerUrl || saveConvertedFileUrl,
      wsslbh: wsslbh,
      targetFormat: 'pdf',
      maxQueryTimes: maxQueryTimes,
      sfyy: sfyy,
      createExtend: createExtend,
    })
  },
  createCloudOfdReader: ({ parentNode, fileDir, fileName, readerServer }) => {
    throw Error('sursen不支持无插件阅读模式')
  },
  createLocalOfdReader: ({
    parentNode,
    fileDir,
    fileName,
    readOnly,
    wrapIframe,
    fileUrl,
    sealId,
  }) => {
    if (!isSursenLocalPluginUsable()) {
      throw Error('本地OFD插件不可用, 请确认已安装OFD客户端')
    }
    if (!parentNode) {
      throw Error('缺少parentNode参数, 必须提供该参数作为阅读器插件的父节点')
    }
    if (!fileUrl && !(fileDir && fileName)) {
      throw Error('必须提供fileUrl或fileDir + fileName 参数标识OFD文档的下载地址')
    }
    console.log(`fileUrl: ${fileUrl}, fileDir: ${fileDir}, fileName: ${fileName}`)

    parentNode.innerHTML = ''

    console.log(parentNode.id)
    const ofd = sursenOfdReader.loadReader(parentNode.id)

    fileUrl = fileUrl || `${window.BASEURL}/wjfw-service/file/get?dir=${fileDir}&name=${fileName}`

    console.log(`预览文件: ${fileUrl}`)
    console.log(`sursen是否以只读模式打开版式文件: ${readOnly ? '是' : '否'}`)

    sursenOfdReader.openOfdFile(ofd, fileUrl, !!readOnly)
    if (!ofd) {
      throw Error(`sursen打开文档失败: ${fileUrl}`)
    }

    ofd.showPlugin = () => {
      parentNode.querySelector('embed').style.visibility = 'visible'
    }
    ofd.hidePlugin = () => {
      parentNode.querySelector('embed').style.visibility = 'hidden'
    }

    return ofd
  },
  // 该接口只能保存由 createLocalOfdReader 接口打开的OFD文档
  saveOpenedOfd: ({ instance, targetDir, targetName, overrideOnExists, saveUrl }) => {
    if (!instance) {
      throw Error('缺少instance参数, 必须提供instance标识要保存的OFD文档实例')
    }

    saveUrl =
      saveUrl ||
      `${window.BASEURL}/wjfw-service/file/save?dir=${targetDir}&name=${targetName}&overrideOnExists=${overrideOnExists}`

    console.log(`保存OFD文档, 保存地址: ${saveUrl}`)

    return sursenOfdReader.saveOfdFile(instance, saveUrl)
  },
  // 该接口只能保存由 createLocalOfdReader 接口打开的OFD文档
  printOpenedOfd: ({ instance, count }) => {
    if (!instance) {
      throw Error('缺少instance参数, 必须提供instance标识要保存的OFD文档实例')
    }
    if (count === null || count === undefined) {
      throw Error(`打印OFD文档时，未传入打印份数: ${count}`)
    }
    if (count < 0) {
      throw Error(`打印OFD文档时，打印份数不能为负数: ${count}`)
    }

    console.debug(`调用OFD阅读器打印接口, 打印份数: ${count}`)

    sursenOfdReader.printOfdFile(instance, count)
  },
  /**
   * name对应的组件：
   * f_open       打开
   * f_import     导入文件
   * f_export     导出文件
   * f_save       保存
   * f_saveas     另存为
   * f_print      打印
   * f_close      关闭
   * d_sealsign   盖章
   * d_verifysign 验章
   * w_menu       显示/隐藏菜单栏
   * w_tool       显示/隐藏工具栏
   * w_statusbar  显示/隐藏底部工具栏
   * w_navigator  显示/隐藏导航栏（文档结构图）
   */
  toggleComponent: ({ instance, name, enable }) => {
    sursenOfdReader.setCompositeVisible(instance, name, enable)
  },
  /**
   * 设置打印弹出对话框的复选框组件的默认值
   * @name 请使用 instance.printOptions 属性里配置的参数项
   */
  setPrintOption: (instance, option, value) => {
    if (!instance) {
      throw Error('缺少instance参数, 必须提供instance标识要保存的OFD文档实例')
    }

    console.warn('书生OFD阅读器暂不支持设置打印窗体的参数')
  },
  printOptions: {
    // true选中灰度打印，false代表取消选中
    gray: 'print_gray',
    // 设置打印的份数，非负整数
    count: 'copies',
  },
  // 以下是批量打印相关接口
  /**
   * 如果是在批量用印时调用该接口，则不传instance参数
   * 如果不是批量用印，则必须传instance参数
   */
  showPrintSetting() {
    sursenOfdReader.showPrintSetting()
  },
  /**
   * 完成文件的批量打印功能.
   *
   * srcFiles     待打印文件数组，支持本地和远程两种方式。
   * printNums    对应文件的打印份数，份数之间也通过份号分隔，与srcFiles中的文件下标一一对应。
   * 返回 {"srcFiles":[,,,],"printNums":[2,1,3]，"sucecss",[true,false,true],"info",['','','']}
   **/
  batchPrint({ srcFiles, printNums }) {
    return sursenOfdReader.batchPrint(srcFiles, printNums)
  },
  getSealCount(instance) {
    if (!instance) {
      throw Error('缺少instance参数, 必须提供instance标识要获取印章数量的OFD文档实例')
    }

    let sealNames = sursenOfdReader.getSealList(instance).trim()
    if (sealNames === '') {
      return 0
    } else {
      console.log(`印章名(分号分隔): ${sealNames}`)
      if (sealNames.length > 0 && sealNames[0] === ';') {
        sealNames = sealNames.substring(1)
      }
      if (sealNames.length > 0 && sealNames[sealNames.length - 1] === ';') {
        sealNames = sealNames.substring(0, sealNames.length - 1)
      }
      return sealNames.split(';').length
    }
  },
  /**
   * @param parentNodeId 父节点ID，父节点的内容会被清空
   * @param srcFileUrl 已用印的文件的下载地址
   * @param mbFileUrls 待批量用印的文件的url地址数组
   * @param saveFileUrls mbFileUrls对应文档用印完成后的保存地址数组，和mbFileUrls一一对应
   */
  batchSeal({ parentNodeId, srcFileUrl, mbFileUrls, saveFileUrls }) {
    if (!parentNodeId) {
      throw Error('缺少parentNodeId参数, 必须提供该参数作为批量用印插件的父节点')
    }
    if (!mbFileUrls || mbFileUrls.length === 0) {
      throw Error('未传入待盖章文件地址数组')
    }
    if (!saveFileUrls) {
      throw Error('未传入文件盖章后的保存地址数组')
    }
    if (mbFileUrls.length !== saveFileUrls.length) {
      throw Error('待盖章文件地址数组和保存地址数组数量不匹配')
    }

    const parentNode = document.querySelector(`#${parentNodeId}`)

    parentNode.innerHTML = ''

    console.log(
      `批量用印, 源文件地址: ${srcFileUrl}, 模板文件地址: ${mbFileUrls}, 保存地址: ${saveFileUrls}`,
    )

    sursenBatchSeal.loadSursenSeal(parentNodeId)
    const result = sursenBatchSeal.sealbyBatch(
      srcFileUrl,
      mbFileUrls.join(';'),
      saveFileUrls.join(';'),
      true,
    )

    return result
  },
  async autoSeal({ parentNodeId, wsInfoArray }) {
    if (!parentNodeId) {
      throw Error('缺少parentNodeId参数, 必须提供该参数作为自动用印插件的父节点')
    }
    if (!wsInfoArray || wsInfoArray.length === 0) {
      throw Error('未传入需自动用印文书信息')
    }

    const parentNode = document.querySelector(`#${parentNodeId}`)

    parentNode.innerHTML = ''

    sursenBatchSeal.loadSursenSeal(parentNodeId)
    const result = sursenBatchSeal.sealbyAuto(
      JSON.stringify({
        wsinfo: wsInfoArray,
        isdebug: true,
      }),
    )

    return result
  },
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

export default fileConverter
